package com.kunlun.gateway.config;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.kunlun.common.constant.AMQPConstant;
import com.netflix.appinfo.InstanceInfo;
import com.rabbitmq.client.Channel;
import io.micrometer.common.util.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springdoc.core.properties.AbstractSwaggerUiConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springdoc.core.utils.Constants;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Configuration
public class SpringDocGatherConfig {

    private Logger log = LogManager.getLogger();

    @Autowired
    private SwaggerUiConfigProperties swaggerUiConfigProperties;
    @Autowired
    private RouteDefinitionLocator locator;

    @RabbitListener(queues = AMQPConstant.SERVICE_REGISTER_QUEUE)
    public void apis(String messages, Channel channel, Message message) {
        log.info("========== receive service register message ==========");
        log.info("DocGatherConfig apis messages => " + messages);
        log.info("DocGatherConfig apis channel => " + JSONObject.toJSONString(channel));
        log.info("DocGatherConfig apis message => " + JSONObject.toJSONString(message));
        InstanceInfo instanceInfo = JSONObject.parseObject(messages, InstanceInfo.class);

        //获取所有的路径配置
        List<RouteDefinition> definitions = locator.getRouteDefinitions().collectList().block();
        log.info("DocIntegrationConfig apis definitions => " + JSONArray.toJSONString(definitions));
        //过滤，只要lb模块式
        List<RouteDefinition> serviceRoutes = definitions.stream().filter(route -> null != route.getUri() && route.getUri().getScheme().equals("lb")).collect(Collectors.toList());
        //按根据PredicateDefinition参数值和/** 确定是否路径匹配
        Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> lbRouteUrl = new HashSet<>();
        Optional.ofNullable(serviceRoutes).orElse(Collections.emptyList()).forEach(route -> {
            AbstractSwaggerUiConfigProperties.SwaggerUrl swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl();
            //获取路径前缀
            List<PredicateDefinition> predicates = route.getPredicates();
            if (null == predicates || predicates.size() <= 0) {
                return;
            }
            String prefix = "";
            for (PredicateDefinition predicate : predicates) {
                String predicateName = predicate.getName();
                if ("path".equalsIgnoreCase(predicateName)) {
                    for (String regex : predicate.getArgs().values()) {
                        if (regex.endsWith("/**")) {
                            prefix = regex.substring(0, regex.length() - 3);
                            continue;
                        }
                    }
                }
            }
            //不是路径匹配的路由，跳过
            if (StringUtils.isBlank(prefix)) {
                return;
            }

            swaggerUrl.setUrl(prefix + Constants.DEFAULT_API_DOCS_URL);
            swaggerUrl.setName(prefix);
            swaggerUrl.setDisplayName(route.getId().split("_")[1].toLowerCase(Locale.ROOT));
            log.info("DocIntegrationConfig apis swaggerUrl => " + JSONObject.toJSONString(swaggerUrl));
            lbRouteUrl.add(swaggerUrl);
        });

        //添加swaggerUI服务集成匹配
        if (lbRouteUrl.size() > 0) {
            Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> propertiesUrls = swaggerUiConfigProperties.getUrls();
            if (null == propertiesUrls || propertiesUrls.size() <= 0) {
                propertiesUrls = lbRouteUrl;
            } else {
                propertiesUrls.addAll(lbRouteUrl);
            }
            swaggerUiConfigProperties.setUrls(propertiesUrls);
        }
    }
}
